package com.lucky.carcodepro.aspectj;

import cn.hutool.core.util.StrUtil;
import com.lucky.carcodepro.common.annotation.DistributedLock;
import lombok.AllArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

/**
 * DistributedLockAspect
 * <p>
 * 描述：分布式锁切面
 *
 * @author Annie
 * @version 2024/10/6 23:54
 */
@Aspect
@Component
@AllArgsConstructor
public class DistributedLockAspect
{
    private final RedissonClient redissonClient;

    @Around("@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable
    {
        // 锁名称
        var lockName = distributedLock.lockName();
        if (StrUtil.isNotBlank(lockName))
        {
            // 未指定锁名称，用方法名，当做锁名
            lockName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        }

        RLock lock;
        if (distributedLock.fairLock())
        {
            // 获取公平锁
            lock = redissonClient.getFairLock(lockName);
        } else
        {
            // 获取普通锁
            lock = redissonClient.getLock(lockName);
        }

        // 锁状态寄存
        var isLocked = false;

        try
        {
            // 尝试获取锁，指定等待时间，-1表示使用看门狗机制自动续期
            isLocked = lock.tryLock(distributedLock.waitTime(), distributedLock.leaseTime(), distributedLock.unit());
            if (isLocked)
            {
                // 抢锁成功, 执行目标方法
                return joinPoint.proceed();
            }
            throw new RuntimeException("无法获取锁: " + lockName);
        } catch (Exception e)
        {
            throw new RuntimeException("执行分布式锁逻辑时发生异常", e);
        } finally
        {
            // 释放锁，避免死锁
            lock.unlock();
        }
    }
}
